StreamCore IPTV Documentation

Version 1.2.0

Updated: March 2026

By: Syruum Team

Support: Use the support system on CodeCanyon

Thank you for purchasing StreamCore IPTV! If you have any questions that are beyond the scope of this documentation, please feel free to contact us via the CodeCanyon support system. We'll do our best to assist you!

StreamCore IPTV Documentation

A comprehensive IPTV/VOD streaming platform with Admin, Reseller, and User panels. Built with Next.js, Rust/Axum, and Kotlin.

Latest Release: v1.2.0 (March 2026)
  • 9+ security fixes: bcrypt API keys, IP spoofing patched, Stripe idempotency, 2FA hardened, rate limiting.
  • End-user subscription system: self-registration, free/paid packages, category-based content access.
  • ClearKey DRM fully fixed across phone and TV apps (DASH manifest parser rewritten).
  • Admin panel: Stripe payment settings UI, per-episode multi-stream, upload progress bars.
  • 77K+ RPS on content endpoints, 82 automated tests, 0 Clippy warnings.
  • Automatic v1.1.2 β†’ v1.2.0 database migration (44 tables, FK-safe ordering).
  • Release docs: Updates Overview and How to Install and Update.
Content & Legal Notice: StreamCore is a self‑hosted platform only and does not include any IPTV lists, streams, channels, EPG sources, or copyrighted media. Use only content you own or are licensed to distribute or view. The author does not condone piracy.
🎬

VOD & Live TV

Movies, Series, Live TV channels with EPG support

πŸ‘₯

Multi-Role System

Admin, Reseller, and End User roles with permissions

πŸ’³

Stripe Payments

Integrated credit purchase system with volume discounts

πŸ“±

Android TV + Phone Apps

Native Kotlin apps for Android TV and Android Phone

System Requirements

Component Requirement Notes
Node.js 20+ (LTS recommended) For frontend build
Rust 1.70+ For backend compilation
RAM 4GB minimum 8GB+ recommended
Storage 20GB+ 100GB+ recommended for media storage
OS Linux, macOS, Windows Linux recommended for production

Installation Overview

StreamCore consists of three main components:

Recommended: Use the Docker flow in How to Install and Update for faster setup, easier usage, and repeatable deployments.

Fastest setup: run the root installer script: sudo bash install.sh. It installs Docker if needed, asks for your config, updates docker-compose.yml, and starts the stack automatically.
βš™οΈ

Backend (Rust)

API server running on port 3000

🌐

Frontend (Next.js)

Web application running on port 5000

Quick Start

⚠️ Configure secrets before starting

Set JWT_SECRET and ADMIN_DEFAULT_PASSWORD in backend/.env before running the backend. Do not use defaults in production.

Terminal
# 1. Start Backend (Terminal 1)
cd backend
cp .env.example .env
cargo build --release
./target/release/iptv-backend

# 2. Start Frontend (Terminal 2)
cd frontend
cp .env.example .env.local
npm install
npm run build
npm run start

Docker Deployment (Recommended)

For production or quick setup, use the included docker-compose.yml and root .env.

Environment File
# From the project root - Docker uses centralized configuration
# Edit docker-compose.yml directly (section x-config at the top)
# Change: postgres_password, jwt_secret, admin_password, domains

# For production with SSL:
# Uncomment the nginx-proxy and acme-companion services
Production (SSL)
# Uses nginx-proxy + Let's Encrypt
docker compose --profile proxy up -d --build
Development (No Proxy)
# Direct ports: 3000 (backend), 5000 (frontend)
docker compose up -d --build
URLs:
  • Production (proxy): https://FRONTEND_DOMAIN and https://BACKEND_DOMAIN
  • Development: http://localhost:5000 and http://localhost:3000

Default Login Credentials

πŸ” Default Admin Account

Username: admin

Password: Set via ADMIN_DEFAULT_PASSWORD in .env, or check console output for auto-generated temporary password

⚠️ Change this password immediately after first login!

See Backend Environment section for details.

πŸ“¦ Database Auto-Creation:
PostgreSQL is created and configured automatically when you start Docker. No manual setup required!
  • PostgreSQL 16 runs in its own container
  • All tables are created via automatic migrations
  • Default admin user is created (password from docker-compose.yml)
  • Default categories are created automatically

Backend Setup (Rust)

1. Install Rust

If you don't have Rust installed, install it using rustup:

Linux/macOS
# Install Rust via rustup (official installer)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Follow the prompts, then reload your shell
source $HOME/.cargo/env

# Verify installation
rustc --version
cargo --version
Windows
# Download and run rustup-init.exe from:
# https://rustup.rs/

# Or use winget:
winget install Rustlang.Rustup

# Restart terminal and verify
rustc --version
cargo --version

2. Configure Environment

Terminal
cd backend

# Copy example environment file
cp .env.example .env

# Edit with your settings
nano .env

3. Build the Backend

Development Build
# Development build (faster compilation, slower runtime)
cargo build

# Run development server
cargo run
Production Build (Recommended)
# Production build (slower compilation, optimized runtime)
cargo build --release

# The binary is located at:
# ./target/release/iptv-backend

# Run production server
./target/release/iptv-backend

4. Verify Backend is Running

Terminal
# Test health endpoint
curl http://localhost:3000/api/health

# Expected response:
# {"status":"ok","message":"IPTV Backend is running"}
πŸ’‘ Tip: The first build may take several minutes as Rust compiles all dependencies. Subsequent builds will be much faster.

Frontend Setup (Next.js)

1. Install Node.js

Install Node.js 20 or later:

Using NVM (Recommended)
# Install NVM
curl -o- https://nvm.sh | bash

# Reload shell
source ~/.bashrc

# Install Node.js LTS (20+)
nvm install --lts
nvm use --lts

# Verify
node --version
npm --version

2. Install Dependencies

Terminal
cd frontend

# Install all dependencies
npm install

3. Configure Environment

Terminal
# Copy example environment file
cp .env.example .env.local

# Edit with your backend URL
nano .env.local
πŸ“„ frontend/.env.local
.env.local
# Backend API URL
# Development:
NEXT_PUBLIC_API_URL=http://localhost:3000

# Production:
# NEXT_PUBLIC_API_URL=https://api.yourdomain.com

⚠️ Production builds

Set NEXT_PUBLIC_API_URL in production so the frontend points to the backend host. If it is missing, the browser falls back to the current site origin, which may not be correct behind a reverse proxy.

4. Run Frontend

Development Mode (with hot reload)

Terminal
# Start development server
npm run dev

# Access at: http://localhost:5000

Production Mode

Terminal
# Build for production
npm run build

# Start production server (port 5000)
npm run start

# Or specify a custom port
PORT=3001 npm run start

# Access at: http://localhost:5000

Available NPM Scripts

Command Description
npm run dev Start development server with hot reload
npm run build Build optimized production bundle
npm run start Start production server (run build first)
npm run lint Run ESLint to check code quality
npm run test Run unit tests with Jest

Database

πŸ—„οΈ PostgreSQL Database
StreamCore uses PostgreSQL 16. With Docker, the database is created and configured automatically. For manual installs, you need to set up PostgreSQL first.

Docker Setup (Automatic)

When using Docker, PostgreSQL is fully managed:

  1. PostgreSQL 16 container starts automatically
  2. Database and user are created from docker-compose.yml settings
  3. Backend waits for PostgreSQL to be ready (healthcheck)
  4. Migrations run automatically on startup

Manual Setup (Without Docker)

Install PostgreSQL
# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib

# Start PostgreSQL
sudo systemctl start postgresql
sudo systemctl enable postgresql

# Create database and user
sudo -u postgres psql
CREATE USER streamcore WITH PASSWORD 'your_password';
CREATE DATABASE streamcore OWNER streamcore;
\q

Database Connection

backend/.env
# Local PostgreSQL
DATABASE_URL=postgres://streamcore:your_password@localhost:5432/streamcore

# Cloud PostgreSQL (Neon)
# DATABASE_URL=postgres://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require

# Cloud PostgreSQL (Supabase)
# DATABASE_URL=postgres://postgres:pass@db.xxx.supabase.co:5432/postgres

Backup Database

PostgreSQL pg_dump
# Manual backup
pg_dump -U streamcore -h localhost streamcore > backup_$(date +%Y%m%d).sql

# Restore from backup
psql -U streamcore -h localhost streamcore < backup_20260209.sql

Automatic backups: The backend can create backups automatically using pg_dump. Configure BACKUP_ENABLED, BACKUP_DIR, BACKUP_RETENTION_DAYS, and BACKUP_INTERVAL_HOURS in docker-compose.yml or backend/.env.

Scaling Options

PostgreSQL supports high concurrency (10,000+ users). For very large deployments, consider:

Systemd Services (Auto-start & Auto-restart)

Configure systemd to automatically start StreamCore on boot and restart if it crashes.

1. Backend Service

Create: /etc/systemd/system/iptv-backend.service
[Unit]
Description=StreamCore Backend (Rust/Axum)
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/streamcore/backend
ExecStart=/var/www/streamcore/backend/target/release/iptv-backend
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=3

# Environment
Environment=RUST_LOG=info

# Security hardening
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

2. Frontend Service

Create: /etc/systemd/system/streamcore-frontend.service
[Unit]
Description=StreamCore Web Frontend (Next.js)
After=network.target
# Optional: if you run the backend as a systemd service, add:
# After=network.target iptv-backend.service
# Wants=iptv-backend.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/streamcore/frontend
ExecStart=/usr/bin/npm run start
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=3

# Environment
Environment=PORT=5000
Environment=NODE_ENV=production

# Security hardening
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

3. Enable and Start Services

Terminal
# Reload systemd to recognize new services
sudo systemctl daemon-reload

# Enable services to start on boot
sudo systemctl enable iptv-backend
sudo systemctl enable streamcore-frontend

# Start services now
sudo systemctl start iptv-backend
sudo systemctl start streamcore-frontend

# Check status
sudo systemctl status iptv-backend
sudo systemctl status streamcore-frontend

4. Useful Commands

Command Description
sudo systemctl start iptv-backend Start the backend service
sudo systemctl stop iptv-backend Stop the backend service
sudo systemctl restart iptv-backend Restart the backend service
sudo systemctl status iptv-backend Check service status
sudo journalctl -u iptv-backend -f View live logs
sudo journalctl -u iptv-backend --since "1 hour ago" View recent logs

5. Auto-Restart Configuration

πŸ”„ Automatic Restart on Crash
The services are configured with:
  • Restart=always - Always restart when the process exits
  • RestartSec=5 - Wait 5 seconds before restarting
  • StartLimitBurst=3 - Max 3 restarts within the interval
  • StartLimitIntervalSec=60 - Reset restart counter after 60 seconds
This prevents infinite restart loops while ensuring the service recovers from crashes.

6. Deploy Script (Optional)

Create a deploy script for rebuilding and restarting services:

/var/www/streamcore/deploy.sh
#!/bin/bash
set -e

echo "πŸš€ Deploying StreamCore..."

# Place release files under /var/www/streamcore before running this script

# Build backend
echo "πŸ“¦ Building backend..."
cd /var/www/streamcore/backend
cargo build --release

# Build frontend
echo "πŸ“¦ Building frontend..."
cd /var/www/streamcore/frontend
npm install
npm run build

# Restart services
echo "πŸ”„ Restarting services..."
sudo systemctl restart iptv-backend
sudo systemctl restart streamcore-frontend

echo "βœ… Deployment complete!"
sudo systemctl status iptv-backend --no-pager
sudo systemctl status streamcore-frontend --no-pager
Make executable
chmod +x /var/www/streamcore/deploy.sh

# Run deployment
./deploy.sh

Change App Name (Branding)

To rebrand the application with your own name, update the following files:

1. Android TV App (Recommended - Dynamic)

The Android TV app uses local.properties for dynamic branding:

πŸ“„ Apps/tv_app/local.properties
local.properties
# App branding name (used throughout the app)
branding.name=Your App Name
βœ… No code changes needed! The app name is automatically applied to all UI elements via BuildConfig.BRANDING_NAME and @string/branding_name.
Android Phone: the phone app has its own local config at Apps/phone_app/local.properties (created from Apps/phone_app/local.properties.template).

2. Frontend - Environment Variable (Recommended)

The frontend app name is centralized via environment variable. Simply set NEXT_PUBLIC_APP_NAME:

πŸ“„ frontend/.env.local
.env.local
# Application name displayed throughout the UI
NEXT_PUBLIC_APP_NAME=Your App Name
βœ… No code changes needed! The app name is automatically applied to:
  • Login page title and footer
  • Sidebar brand name
  • Demo signup page
  • Email settings default values
All translation files use {{appName}} placeholder which is automatically replaced.

⚠️ Docker Users: Rebuild Required

When using Docker, the APP_NAME is set in the root .env file and is baked into the frontend at build time. After changing APP_NAME, you must rebuild the frontend container:

docker compose build --no-cache frontend && docker compose up -d frontend

3. Frontend - Login Page Logo & Branding

The login page displays the app logo in the header with a slate-800 backdrop container. To customize:

πŸ“„ frontend/src/app/login/page.tsx

Logo Image

The login page uses /logo.png from the public folder:

Login Logo Configuration
<Image 
  src="/logo.png" 
  alt="StreamCore Logo"
  width={48}
  height={48}
  className="object-contain"
  priority
/>

Simply replace the public/logo.png file with your custom logo (same as used in the sidebar and documentation).

Logo Container Style

The logo sits in a slate-dark container with a cyan-to-purple gradient glow effect:

Container Styling (login/page.tsx)
// Glow effect (background)
<div className="absolute inset-0 bg-gradient-to-r from-cyan-400 to-purple-600 rounded-2xl blur-xl opacity-75 animate-pulse"></div>

// Container
<div className="relative bg-slate-800/80 backdrop-blur-md p-4 rounded-2xl">

To change the container color, edit bg-slate-800/80 to any Tailwind color. To change the glow colors, modify the gradient colors (from-cyan-400 to-purple-600).

Login Page Branding Text

The app name in login, sidebar, and other UI elements is automatically set from the NEXT_PUBLIC_APP_NAME environment variable (see section 2 above). No need to edit translation files manually.

4. Frontend - PWA Manifest

πŸ“„ frontend/public/manifest.json
manifest.json
{
  "name": "StreamCore IPTV",
  "short_name": "StreamCore",
  "description": "Professional IPTV/VOD streaming platform"
}

5. Backend Banner (Optional)

πŸ“„ backend/src/main.rs

Search for the ASCII banner and replace "StreamCore" with your app name.

Quick Find & Replace

To find all occurrences of "StreamCore" in the frontend:

Terminal
# Find all StreamCore references
grep -r "StreamCore" frontend/src/

# Replace all (use with caution)
find frontend/src -type f -name "*.tsx" -o -name "*.json" | xargs sed -i 's/StreamCore/YourAppName/g'

Backend Environment

Docker tip: If you deploy via Docker, configure the root .env file (see How to Install and Update) instead of editing backend/.env directly.

Configure the backend by editing backend/.env:

πŸ“„ backend/.env

Database Configuration

.env
# PostgreSQL (recommended)
DATABASE_URL=postgres://streamcore:change_me@localhost:5432/streamcore

# Docker internal network example
# DATABASE_URL=postgres://streamcore:change_me@postgres:5432/streamcore

Server Configuration

Variable Description Example
SERVER_ADDRESS IP and port for the backend server 0.0.0.0:3000
PUBLIC_BASE_URL Public URL for generating stream links https://api.yourdomain.com
JWT_SECRET Secret key for JWT tokens (min 32 chars) Generate with: openssl rand -hex 32

Stripe Payments (Optional)

.env
# Get these from Stripe Dashboard > Developers > API keys
STRIPE_SECRET_KEY=sk_live_your_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret

# Redirect URLs after payment
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel

# Currency (lowercase ISO code)
STRIPE_CURRENCY=usd
Stripe Webhook URL:
Configure the webhook endpoint in your Stripe Dashboard > Developers > Webhooks.
Endpoint URL: https://api.yourdomain.com/api/payments/stripe/webhook

Additional Configuration

Variable Description Default
SKIP_MIGRATIONS Skip automatic database migrations on startup false
CONTENT_OVERVIEW_MULTIPLIER Multiplier for content count display (x1, x2, 1.5) x1
RUST_LOG Logging level (trace, debug, info, warn, error) info
DEBUG_MODE Enable verbose debug behaviors (development only) false
CORS_ALLOWED_ORIGINS Comma-separated list of allowed origins for CORS (production security) * (dev) or https://yourdomain.com
BACKUP_ENABLED Enable automatic PostgreSQL backups (pg_dump) true
BACKUP_DIR Directory for backup files ./backups
BACKUP_RETENTION_DAYS Days to keep backups 30
BACKUP_INTERVAL_HOURS Backup interval in hours 24

Default Admin Password

The admin user is created automatically when the database is initialized for the first time. The password can be configured in two ways:

Option 1: Set Password via Environment Variable (Recommended)

Define ADMIN_DEFAULT_PASSWORD in your .env file before starting the backend for the first time:

backend/.env
# Default admin password (set before first run)
ADMIN_DEFAULT_PASSWORD=your_secure_password_here

Option 2: Auto-Generated Temporary Password

If ADMIN_DEFAULT_PASSWORD is not set, the backend will generate a unique temporary password and display it in the console output:

Console Output (first run only)
⚠️  IMPORTANT: Generated temporary admin password: tmp_187cef55b6584fdf
⚠️  Please change this password immediately after first login!
⚠️  Or set ADMIN_DEFAULT_PASSWORD environment variable before first run.
πŸ‘€ Created default admin user 'admin'

⚠️ Important

The temporary password is only displayed once during the first database creation. If you miss it, you'll need to reset the password manually.

Reset Admin Password Manually

If you forgot the admin password or need to reset it:

Terminal
# 1. Generate a bcrypt hash for your new password
python3 -c "import bcrypt; print(bcrypt.hashpw(b'YOUR_NEW_PASSWORD', bcrypt.gensalt()).decode())"

# 2. Update the database with the new hash
docker exec -it streamcore-postgres psql -U <POSTGRES_USER> -d <POSTGRES_DB> -c \
"UPDATE users SET password_hash='PASTE_HASH_HERE' WHERE username='admin';"

# 3. Restart the backend

Reset Database Completely

To start fresh with a new database (all data will be lost):

Terminal
# Docker deployment (recommended)
docker compose down -v
docker compose up -d --build

# This recreates PostgreSQL volumes and all services from scratch.

Full Example

backend/.env (complete)
# Database
DATABASE_URL=postgres://streamcore:change_me@localhost:5432/streamcore

# Server
SERVER_ADDRESS=0.0.0.0:3000
PUBLIC_BASE_URL=https://api.yourdomain.com

# Security (REQUIRED - generate unique value!)
JWT_SECRET=your_64_character_random_hex_string_here
ADMIN_DEFAULT_PASSWORD=change_me_before_first_run

# Logging
RUST_LOG=iptv_backend=info,tower_http=warn,sqlx=warn
SKIP_MIGRATIONS=false
DEBUG_MODE=false

# Backups (PostgreSQL pg_dump)
BACKUP_ENABLED=true
BACKUP_DIR=./backups
BACKUP_RETENTION_DAYS=30
BACKUP_INTERVAL_HOURS=24

# Content Display
CONTENT_OVERVIEW_MULTIPLIER=x1

# CORS (production: specify allowed origins)
CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://api.yourdomain.com

# Stripe Payments (leave empty to disable)
STRIPE_SECRET_KEY=sk_live_xxx
STRIPE_WEBHOOK_SECRET=whsec_xxx
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel
STRIPE_CURRENCY=usd
Note: Email settings like frontend_url and app_name are configured via the Admin Panel under Email Settings and stored in the database. UI branding still uses NEXT_PUBLIC_APP_NAME in the frontend environment.

Frontend Environment

Docker tip: In Docker, these values come from the root .env. Use frontend/.env.local only for non-Docker installs.

Configure the frontend by editing frontend/.env.local:

πŸ“„ frontend/.env.local
.env.local
# Backend API URL
# Development: http://localhost:3000
# Production: https://api.yourdomain.com
NEXT_PUBLIC_API_URL=https://api.yourdomain.com

# Optional server-only base URL for Next.js (Docker/private network)
# Docker: http://backend:3000
# Local: http://localhost:3000
INTERNAL_API_URL=http://backend:3000

# Application name (displayed in UI - login, sidebar, footer, etc.)
# Default: StreamCore
NEXT_PUBLIC_APP_NAME=StreamCore

# Debug logging (optional - enables verbose console logs)
NEXT_PUBLIC_DEBUG_LOGS=false

# Media/subtitle proxy allowlist (server-only)
# Comma-separated hostnames, or "*" for local development
STREAMCORE_PROXY_ALLOWED_HOSTS=
STREAMCORE_PROXY_REQUIRE_AUTH=true
STREAMCORE_PROXY_ALLOW_PRIVATE=false
Important: The NEXT_PUBLIC_ prefix is required for environment variables to be accessible in the browser.

Build Commands

Terminal
# Development (hot reload)
npm run dev

# Production build
npm run build

# Start production server (port 5000 by default)
npm run start

# Or specify a custom port
PORT=3001 npm run start

Android Phone App Configuration NEW

Configure the Android Phone application using local.properties:

1. Create local.properties

Terminal
cd app_phone/phone_app

# Copy the template
cp local.properties.template local.properties

# Edit with your settings
nano local.properties

2. Configure Branding & Backend URL

πŸ“„ app_phone/phone_app/local.properties
local.properties
# Android SDK (auto-configured by Android Studio)
sdk.dir=/path/to/your/android/sdk

# App Branding Name
branding.name=Your App Name

# Backend URL (without /api suffix)
# Development with emulator:
backend.url=http://10.0.2.2:3000

# Production:
# backend.url=https://api.yourdomain.com
πŸ”§ Generated Build Config Fields:
  • BuildConfig.BRANDING_NAME = branding.name
  • BuildConfig.API_BASE_URL = backend.url + "/api/"
  • BuildConfig.STREAM_BASE_URL = backend.url + "/stream/"
  • R.string.branding_name = branding.name (for XML usage)

3. Change Package Name (applicationId)

To rebrand the app with your own package name:

Step 1: Update build.gradle

πŸ“„ app_phone/phone_app/app/build.gradle
build.gradle
android {
    namespace 'com.yourcompany.yourapp'  // Change this
    
    defaultConfig {
        applicationId "com.yourcompany.yourapp"  // Change this
        ...
    }
}

Step 2: Rename Package Folders

Terminal
# Rename the package directory structure
cd app_phone/phone_app/app/src/main/java

# Current: com/streamcore/phone/
# New: com/yourcompany/yourapp/

mv com/streamcore com/yourcompany
mv com/yourcompany/phone com/yourcompany/yourapp

Step 3: Update Imports (Android Studio)

In Android Studio: Edit β†’ Find β†’ Replace in Path

4. Customizing App Identity (Name, Logo, Firebase)

A. Change App Name

The app name is set in two places. First, in your local.properties:

local.properties
branding.name=My Cool App

Second, ensure the XML string is correct by editing:

πŸ“„ app_phone/phone_app/app/src/main/res/values/strings.xml
strings.xml
<resources>
    <string name="app_name">@string/branding_name</string>
</resources>

B. Change App Logo and Icons

The Android Phone app uses standardized Android icons. To replace them with your own logo:

  1. In Android Studio, right click on the app folder and go to New β†’ Image Asset.
  2. Set "Icon Type" to Launcher Icons (Adaptive and Legacy).
  3. Set your logo image in the "Foreground Layer".
  4. Set your desired background color in the "Background Layer".
  5. Click Next and Finish. This will overwrite the default StreamCore icons in the mipmap folders.

C. Configure Google Services (Crashlytics / Firebase)

The app is configured to use Firebase Crashlytics to catch crashes. You must provide your own google-services.json file, or the app will not compile.

  1. Go to the Firebase Console and create a new project.
  2. Add an Android App to the Firebase project. Crucial: Use the exact Package Name (applicationId) you configured in Step 3.
  3. Download the `google-services.json` file.
  4. Place the downloaded google-services.json file directly inside the app_phone/phone_app/app/ directory, replacing the dummy file.

5. Customize Theme Colors

Change the app's modern Jetpack Compose color scheme by editing:

πŸ“„ app_phone/phone_app/app/src/main/java/.../theme/Color.kt

The Android Phone app uses Material 3 dynamic theming internally, but bases its core palette off the definitions in Color.kt.

6. Build APK

The Phone project is configured to output a Single Universal APK rather than architecture splits.

Terminal
cd app_phone/phone_app

# Debug build
./gradlew assembleDebug

# Release build
./gradlew assembleRelease

# The final Universal APK will be output at:
# app/build/outputs/apk/release/app-release.apk

Android TV App Configuration

Configure the Android TV application using local.properties:

1. Create local.properties

Terminal
cd Apps/tv_app

# Copy the template
cp local.properties.template local.properties

# Edit with your settings
nano local.properties

2. Configure Branding & Backend URL

πŸ“„ Apps/tv_app/local.properties
local.properties
# Android SDK (auto-configured by Android Studio)
sdk.dir=/path/to/your/android/sdk

# App Branding Name
branding.name=Your App Name

# Backend URL (without /api suffix)
# Development with emulator:
backend.url=http://10.0.2.2:3000

# Production:
# backend.url=https://api.yourdomain.com

# Local network testing:
# backend.url=http://192.168.1.100:3000
πŸ”§ Generated Build Config Fields:
  • BuildConfig.BRANDING_NAME = branding.name
  • BuildConfig.API_BASE_URL = backend.url + "/api/"
  • BuildConfig.STREAM_BASE_URL = backend.url + "/stream/"
  • R.string.branding_name = branding.name (for XML usage)

3. Configuration Priority

The backend URL is resolved in this order:

  1. local.properties β†’ backend.url
  2. Environment variable β†’ IPTV_BACKEND_URL
  3. Default β†’ http://localhost:3000

4. App Name in strings.xml (Optional Override)

The app name is automatically set from branding.name. For additional string customization:

πŸ“„ Apps/tv_app/app/src/main/res/values/strings.xml
strings.xml
<resources>
    <!-- Uses @string/branding_name from local.properties by default -->
    <string name="app_name">@string/branding_name</string>
</resources>

5. Change Package Name (applicationId)

To rebrand the app with your own package name:

Step 1: Update build.gradle

πŸ“„ Apps/tv_app/app/build.gradle
build.gradle
android {
    namespace 'com.yourcompany.yourapp'  // Change this
    
    defaultConfig {
        applicationId "com.yourcompany.yourapp"  // Change this
        ...
    }
}

Step 2: Rename Package Folders

Terminal
# Rename the package directory structure
cd Apps/tv_app/app/src/main/java

# Current: com/iptv/android/
# New: com/yourcompany/yourapp/

mv com/iptv com/yourcompany
mv com/yourcompany/android com/yourcompany/yourapp

Step 3: Update Imports (Android Studio)

In Android Studio: Edit β†’ Find β†’ Replace in Path

6. Customize Colors & Theme

Change the app's color scheme by editing:

πŸ“„ Apps/tv_app/app/src/main/res/values/colors.xml
colors.xml - Main colors to change
<!-- Brand Colors -->
<color name="brand_primary">#1976D2</color>      <!-- Primary brand color -->
<color name="brand_primary_dark">#1565C0</color> <!-- Darker variant -->
<color name="brand_secondary">#FF6B35</color>    <!-- Accent color -->

<!-- Background Colors -->
<color name="background">#0A0A0A</color>         <!-- Main background -->
<color name="surface">#1A1A1A</color>            <!-- Card/surface background -->

7. Logo Background Colors (Splash & Login Screens)

The app uses a radial gradient background for the logo on Splash and Login screens. You can customize these colors by editing:

πŸ“„ Apps/tv_app/app/src/main/res/values/colors.xml
colors.xml - Logo Background Gradient
<!-- Logo Background Colors (Splash & Login screens) -->
<color name="logo_background_start">#4F46E5</color>   <!-- Gradient center (light) -->
<color name="logo_background_middle">#3730A3</color>  <!-- Gradient middle -->
<color name="logo_background_end">#1E1B4B</color>     <!-- Gradient edge (dark) -->

How the Logo Background Works

Customize the Logo Background Color

Simply edit the three color values to create your own custom gradient:

Example: Purple to Blue Gradient
<color name="logo_background_start">#9F7AEA</color>   <!-- Light purple -->
<color name="logo_background_middle">#7C3AED</color>  <!-- Medium purple -->
<color name="logo_background_end">#3B82F6</color>     <!-- Blue -->

For a Solid Color (No Gradient)

Use the same color for all three values:

Example: Solid Indigo
<color name="logo_background_start">#4F46E5</color>
<color name="logo_background_middle">#4F46E5</color>
<color name="logo_background_end">#4F46E5</color>

Update Logo Image

The logo image itself comes from the adaptive icon foreground. Replace the PNG files at:

The client only needs to replace these PNG files to change the logo in Splash and Login screens without any code changes.

8. Release Signing Configuration

To build a signed APK for Google Play Store:

Step 1: Generate Keystore

Terminal
keytool -genkey -v -keystore my-release-key.keystore \
  -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

Step 2: Configure Signing in build.gradle

app/build.gradle
android {
    signingConfigs {
        release {
            storeFile file('my-release-key.keystore')
            storePassword 'your-store-password'
            keyAlias 'my-key-alias'
            keyPassword 'your-key-password'
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

⚠️ Security Warning

Never commit your keystore or passwords to version control. Use environment variables or a separate keystore.properties file.

9. Build APK

Terminal
cd Apps/tv_app

# Debug build
./gradlew assembleDebug

# Release build (signed)
./gradlew assembleRelease

# APK locations:
# Debug: app/build/outputs/apk/debug/app-debug.apk
# Release: app/build/outputs/apk/release/app-release.apk

10. Android App Features

πŸ“Ί

Live TV

Channel switching, EPG guide, favorites

🎬

VOD Playback

Movies, Series with seasons/episodes

πŸ”

DRM Support

Widevine, ClearKey; PlayReady best-effort on Android

🌐

Multi-language

English, Spanish, Chinese

11. System Requirements

Requirement Value
Minimum Android Version Android 7.0 (API 24)
Target Android Version Android 15 (API 35)
Kotlin Version 2.0+
Gradle Version 8.7+
Android Studio Koala (2024.1) or newer

12. Third-Party Libraries & Credits

Library Purpose License
Jetpack Compose Modern UI toolkit Apache 2.0
AndroidX Media3 Video playback (ExoPlayer successor) Apache 2.0
Hilt Dependency injection Apache 2.0
Retrofit HTTP client Apache 2.0
Coil Image loading Apache 2.0
Room Local database Apache 2.0
DataStore Preferences storage Apache 2.0
Timber Logging Apache 2.0
FFmpeg Extension Software audio/video decoding LGPL 2.1

13. Project Structure

Android App Structure
Apps/tv_app/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ src/main/
β”‚   β”‚   β”œβ”€β”€ java/com/iptv/android/
β”‚   β”‚   β”‚   β”œβ”€β”€ core/           # Constants, utilities, network
β”‚   β”‚   β”‚   β”œβ”€β”€ data/           # Repository implementations, DTOs
β”‚   β”‚   β”‚   β”œβ”€β”€ domain/         # Use cases, models, interfaces
β”‚   β”‚   β”‚   └── presentation/   # UI components, ViewModels, screens
β”‚   β”‚   └── res/
β”‚   β”‚       β”œβ”€β”€ values/         # Colors, strings, themes
β”‚   β”‚       β”œβ”€β”€ mipmap-*/       # App icons
β”‚   β”‚       └── xml/            # Network security config
β”‚   β”œβ”€β”€ build.gradle            # App-level build config
β”‚   └── proguard-rules.pro      # Code obfuscation rules
β”œβ”€β”€ build.gradle                # Project-level build config
β”œβ”€β”€ local.properties            # Local configuration (not in package)
└── local.properties.template   # Template for local config

Admin Panel Features

Access the admin panel at /admin after logging in as admin. The admin panel provides complete control over the platform.

πŸ” Default Admin Credentials
Username: admin
Password: Set via ADMIN_DEFAULT_PASSWORD in .env, or check backend console for auto-generated temporary password
⚠️ Change this password immediately after first login!

Dashboard Overview

The dashboard provides real-time statistics including:

Additional features are available in separate tabs:

User Management

Manage all end users from Admin β†’ Users:

Create New User

  1. Click "Add User" button
  2. Enter username (unique identifier)
  3. Set password (min 6 characters)
  4. Set max devices (1-10)
  5. Optional: set expiry date/time
  6. Optional: assign to reseller and select categories
  7. Click "Create User"

Edit User

Reseller Management

Manage resellers from Admin β†’ Resellers:

Content Management

Manage all streaming content from Admin β†’ Content:

Content Types

Type Description Features
Movies (VOD) Single video content TMDB metadata, posters, trailers
Series Episodes organized by seasons Auto-episode numbering, TMDB integration
Live TV Live streaming channels EPG integration, categories
Events Time-limited live streams PPV support, scheduled visibility
Kids Child-friendly content Parental filtering, dedicated section
Anime Anime-specific content Separate anime section

Adding Content

  1. Click "Add Content" β†’ Select type
  2. Enter title and description
  3. Paste stream URL (HLS/DASH/Direct)
  4. Add poster/backdrop images (URL or upload)
  5. Select category and tags
  6. Enable/disable visibility
  7. Save content

TMDB Integration

Auto-fetch metadata from The Movie Database:

  1. Click "Search TMDB" when adding content
  2. Enter movie/series name
  3. Select from results
  4. Metadata auto-fills (title, description, poster, year, rating)

⚠️ TMDB Usage for Commercial Products

  • TMDB API keys are not bundled. Each buyer must add their own key in the admin panel.
  • Using TMDB data in commercial products requires complying with TMDB's Terms of Service; obtain permission if your usage needs it.
  • Add TMDB's required attribution in your live site: "This product uses the TMDB API but is not endorsed or certified by TMDB."
  • Only import artwork/metadata when you have rights to use it; remove or replace any unlicensed images before going live.

Media Scanner

Bulk import content from local folders:

  1. Go to Admin β†’ Media Scanner
  2. Enter folder path on server
  3. Select content type (Movies/Series/Kids/Anime)
  4. Enable TMDB auto-match (optional)
  5. Click "Scan" to import all files
File Naming Conventions

The scanner extracts title and year from filenames. Use these formats:

Movies / Kids / Anime:

/media/movies/
β”œβ”€β”€ Bureau 749 (2024).mp4
β”œβ”€β”€ Dracula (2025).mkv
β”œβ”€β”€ Frozen (2013).mp4
└── Coco (2017).mp4

Format: Title (Year).extension

TV Series:

/media/tvshows/
β”œβ”€β”€ Breaking Bad S01E01.mp4
β”œβ”€β”€ Breaking Bad S01E02.mp4
β”œβ”€β”€ Game of Thrones S01E01.mkv
└── The Office S02E05.mp4

Format: Show Name S##E##.extension

Alternative Series Structure (folder-based):

/media/tvshows/
└── Breaking Bad/
    β”œβ”€β”€ Season 1/
    β”‚   β”œβ”€β”€ S01E01.mp4
    β”‚   └── S01E02.mp4
    └── Season 2/
        └── S02E01.mp4

Supported Extensions: .mp4, .mkv, .avi, .mov, .webm, .m4v, .ts

Media Watcher

Auto-import new files when added to watched folders:

  1. Go to Admin β†’ Media Watcher
  2. Add folder paths to monitor
  3. Set content type for each folder
  4. Enable watcher
  5. New files are automatically imported

EPG Management

Electronic Program Guide for Live TV:

  1. Go to Admin β†’ EPG Sources
  2. Add EPG URL (XMLTV format)
  3. Set refresh interval (minutes)
  4. Map channels to EPG IDs
  5. EPG auto-updates on schedule

Security Panel

Monitor and manage security from Admin β†’ Security:

System Configuration

Global settings from Admin β†’ Settings:

Additional Admin Features

The admin panel includes these additional management features:

Reseller Panel Features

Resellers can manage their own users, purchase credits, and track their business performance. Access at /reseller after logging in as a reseller.

πŸ’° Fintech-Style Dashboard
The reseller panel features a modern wallet-style interface with real-time statistics, quick actions, and comprehensive analytics.

Dashboard Overview

The reseller dashboard displays:

End User Management

Create and manage users from Reseller β†’ Users:

Create New User

  1. Click "Create User" button
  2. Enter unique username (real-time availability check)
  3. Set password (or auto-generate)
  4. Optional: Enter email (for password reset)
  5. Select subscription duration: 1-12 months
  6. Set device limit: 3, 5, 6, 7, 8, 9, or 10 devices
  7. Select content categories to assign
  8. Click "Create" - credits are deducted automatically

User Actions

Credit System

Credits are the currency for creating and extending users. The cost is calculated based on months and device count:

Credit Calculation Formula

Credit Cost Formula
Base: 1 credit per month for 3 devices
Extra devices: +0.25 credits per month for each device above 3

Formula: months Γ— (1 + (devices - 3) Γ— 0.25)

Example Calculations

Months Devices Credits
1 month 3 devices 1 credit
1 month 5 devices 1.5 credits
6 months 3 devices 6 credits
6 months 5 devices 9 credits
12 months 10 devices 33 credits

Buy Credits

  1. Click "Add Credits" or go to Reseller β†’ Buy Credits
  2. Select credit package or enter custom amount
  3. Volume discounts apply automatically (default tiers, configurable in Admin Panel):
    • 100+ credits: 5% discount
    • 250+ credits: 7% discount
    • 500+ credits: 10% discount
    • 1000+ credits: 15% discount
  4. Proceed to Stripe Checkout
  5. Complete payment - credits added instantly

Demo Management

Resellers can offer limited-time demos:

Activity Logs

Track all actions from Reseller β†’ Activity:

Expiration Monitoring

Monitor user expirations from Reseller β†’ Expiring. Users are categorized by urgency:

Support Tickets

Contact admin support from Reseller β†’ Support:

  1. Click "New Ticket"
  2. Select category (Billing, Technical, Other)
  3. Describe your issue
  4. Submit - admin receives notification
  5. Track ticket status and responses

Reseller API Keys

Resellers can create API keys to integrate their own payment systems and automate user management through the Public API v1. This allows resellers to build custom billing workflows, integrate with payment gateways, and manage users programmatically.

πŸ”‘ API Key System Overview
API Keys allow resellers to call the Public API (/api/v1/*) from their own systems. This is useful for:
  • Integrating with custom payment processors (PayPal, MercadoPago, etc.)
  • Building automated billing systems
  • Creating users automatically after payment confirmation
  • Extending subscriptions via webhooks
  • Building custom reseller dashboards

Accessing API Key Management

Navigate to Reseller β†’ API Keys in the reseller dashboard.

Creating an API Key

  1. Click "Create API Key" button
  2. Enter a descriptive Key Name (e.g., "Payment Webhook", "External System")
  3. Select Permissions:
    • users:read - List and view users
    • users:create - Create new users
    • users:update - Update user status and extend subscriptions
    • users:extend - Extend user subscriptions
    • users:delete - Delete users
    • users:categories - Manage user content categories
    • credits:read - View credit balance and calculate costs
    • categories:read - List available content categories
    • demos:read - List and view demo users
    • demos:create - Create demo users (free, time-limited)
    • demos:delete - Delete demo users
  4. Configure Allowed Origins (CORS):
    • * - Allow from any origin (development only; not recommended for production)
    • https://your-domain.com - Restrict to specific domain
    • Multiple origins: https://domain1.com,https://domain2.com or JSON array
    • Empty or invalid allowed_origins values are rejected
  5. Optional: Add IP Whitelist for additional security
  6. Configure Rate Limits:
    • Requests per minute (default: 60)
    • Requests per day (default: 10,000)
  7. Optional: Set Expiration Date
  8. Click "Create Key"

⚠️ Important: Save Your Secret Key!

The full API key is shown only once when created. Copy and store it securely - you won't be able to see it again.

If you lose the key, you'll need to regenerate it (which invalidates the old key).

API Key Security Features

Feature Description
SHA-256 Hashing API keys are hashed before storage - even database access won't reveal keys
Prefix Display Only first 8 characters are visible for identification
CORS Validation Requests are validated against allowed origins
IP Whitelist Optional restriction to specific IP addresses
Rate Limiting Per-minute and per-day limits enforced per key and per IP
Usage Logging All API key requests are logged; failures block the request
Expiration Optional automatic key expiration
Permission Scopes Granular permissions for each key
Audit Logging All API operations are logged

Managing API Keys

From the API Keys dashboard you can:

Using the API Key

Include the API key in the X-API-Key header for all Public API v1 requests:

Request Header
X-API-Key: your-api-key-here

Example: Create User After Payment

cURL Example
# Create a new user via API
curl -X POST https://your-domain.com/api/v1/users \
  -H "Content-Type: application/json" \
	  -H "X-API-Key: your-api-key-here" \
  -d '{
    "username": "newuser123",
    "password": "securepassword",
    "subscription_months": 3,
    "max_devices": 5
  }'

Example: Extend Subscription (Webhook)

JavaScript/Node.js Example
// Payment webhook handler
async function handlePaymentWebhook(payment) {
  const userId = payment.metadata.user_id;
  const months = payment.metadata.months;
  
  const response = await fetch(`https://your-domain.com/api/v1/users/${userId}/extend`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.STREAMCORE_API_KEY
    },
    body: JSON.stringify({
      days: months * 30
    })
  });
  
  if (response.ok) {
    console.log('Subscription extended successfully');
  }
}

Example: Check Credit Balance

Python Example
import requests

API_KEY = "your-api-key-here"
BASE_URL = "https://your-domain.com/api/v1"

# Get credit balance
response = requests.get(
    f"{BASE_URL}/credits/balance",
    headers={"X-API-Key": API_KEY}
)

data = response.json()
print(f"Available credits: {data['balance']}")

Best Practices

User Panel Features

End users access streaming content through a modern, responsive interface at /user. The interface is optimized for both desktop and mobile devices.

Home Dashboard

The user home page features:

Content Browsing

Movies (VOD)

Series

Live TV

Video Player

Modern player with full controls:

Favorites

Save content for quick access:

  1. Click the heart icon on any content
  2. Access favorites from User β†’ Favorites
  3. Remove by clicking heart again

Watch Progress & Resume

Automatic progress tracking with resume functionality:

Device Management

Manage registered devices from User β†’ Devices:

πŸ“± Device Registration
New devices are registered automatically on first login. If you reach your device limit, remove an old device before logging in on a new one.

Profile Settings

Manage your account from User β†’ Profile:

Language Selection: Switch interface language (EN, ES, ZH) from the Home or Devices page.

πŸ” Two-Factor Authentication
2FA is available only for Admin and Reseller accounts. Regular end users do not have access to 2FA settings.

Content Pages & Routes

The user panel includes these content pages:

Search

Global search across all content:

Additional Public Pages

These pages are accessible without user login:

Stripe Payments Setup

Enable credit purchases for resellers via Stripe Checkout.

1. Create Stripe Account

  1. Go to stripe.com and create an account
  2. Complete business verification
  3. Get your API keys from Dashboard β†’ Developers β†’ API keys

2. Configure Webhook

  1. Go to Dashboard β†’ Developers β†’ Webhooks
  2. Click "Add endpoint"
  3. URL: https://api.yourdomain.com/api/payments/stripe/webhook
  4. Select event: checkout.session.completed
  5. Copy the webhook signing secret

3. Update Environment

backend/.env
STRIPE_SECRET_KEY=sk_live_your_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_signing_secret
STRIPE_SUCCESS_URL=https://yourdomain.com/credits/success
STRIPE_CANCEL_URL=https://yourdomain.com/credits/cancel
STRIPE_CURRENCY=usd

4. Configure Pricing

In Admin Panel β†’ System Configuration β†’ Credits Pricing:

Email (SMTP) Configuration

Configure SMTP to enable password reset emails and 2FA notifications.

πŸ“§ Admin Panel Configuration
SMTP is configured entirely from the Admin Panel. No environment variables required!

Go to: Admin Panel β†’ Settings β†’ Email Configuration

Configuration Steps

  1. Log in as Admin
  2. Navigate to Admin Panel β†’ Settings β†’ Email
  3. Enable SMTP and fill in the settings
  4. Click "Test Connection" to verify
  5. Save the configuration

Required Settings

Field Description Example
SMTP Host Mail server hostname smtp.gmail.com
Port SMTP port (usually 587 for TLS) 587
Username SMTP authentication username your-email@gmail.com
Password SMTP password or app password xxxx xxxx xxxx xxxx
From Name Display name in emails StreamCore
From Email Sender email address noreply@yourdomain.com
Use TLS Enable TLS encryption Yes
Frontend URL Used in password reset links https://yourdomain.com
App Name Used in email subjects and 2FA StreamCore

Gmail Setup

To use Gmail as your SMTP server:

  1. Enable 2-Step Verification in your Google Account
  2. Go to Google App Passwords
  3. Generate a new App Password for "Mail"
  4. Use that 16-character password as SMTP_PASSWORD

Other SMTP Providers

Provider Host Port Notes
Gmail smtp.gmail.com 587 Requires App Password
SendGrid smtp.sendgrid.net 587 Use API key as password
Mailgun smtp.mailgun.org 587 Domain-specific credentials
Amazon SES email-smtp.{region}.amazonaws.com 587 SMTP credentials from AWS console
πŸ“§ Email Features:
  • Password reset emails with secure tokens
  • 2FA enabled/disabled confirmation emails
  • Beautiful HTML email templates

Two-Factor Authentication (2FA)

StreamCore supports TOTP-based two-factor authentication for enhanced account security.

πŸ‘₯ Availability: Two-factor authentication is available for Admin and Reseller accounts only. End users do not have access to 2FA.

How It Works

  1. Setup: User scans QR code with authenticator app (Google Authenticator, Authy, etc.)
  2. Verification: User enters 6-digit code to enable 2FA
  3. Login: After password, user must enter current 2FA code
  4. Backup Codes: 8 one-time backup codes are generated for recovery

User Experience

πŸ”

Enable 2FA

Users enable 2FA from their profile settings page

πŸ“±

Authenticator App

Compatible with Google Authenticator, Authy, Microsoft Authenticator

πŸ”‘

Backup Codes

8 one-time backup codes for account recovery

πŸ“§

Email Notifications

Users receive email when 2FA is enabled/disabled

API Endpoints

Method Endpoint Description
GET /api/auth/2fa/status Get 2FA status for current user
POST /api/auth/2fa/setup Generate secret and QR code
POST /api/auth/2fa/verify Verify code and enable 2FA
POST /api/auth/2fa/disable Disable 2FA (requires code)
POST /api/auth/2fa/backup-codes Regenerate backup codes

Password Reset

Users can reset their password via email:

  1. User clicks "Forgot Password" on login page
  2. User enters their email address
  3. System sends email with secure reset link (expires in 1 hour)
  4. User clicks link and sets new password
Password Reset API Endpoints
POST /api/auth/forgot-password     # Request reset email
POST /api/auth/verify-reset-token  # Verify token validity
POST /api/auth/reset-password      # Set new password

⚠️ Security Notes

  • Reset tokens expire after 1 hour
  • Each token can only be used once
  • All previous tokens are invalidated when a new one is generated
  • SMTP must be configured for password reset to work

Security Best Practices

⚠️ Critical Security Steps

  1. Change default admin password immediately after installation
  2. Generate unique JWT_SECRET: openssl rand -hex 32
  3. Use HTTPS in production (via nginx/Caddy reverse proxy)
  4. Configure CORS to only allow your domain

CORS Configuration

CORS is configured via environment variable. Set CORS_ALLOWED_ORIGINS in your .env file:

backend/.env
# Development (allow all origins - NOT for production!)
CORS_ALLOWED_ORIGINS=*

# Production (comma-separated list of allowed origins)
CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://api.yourdomain.com

⚠️ Security Warning

Never use CORS_ALLOWED_ORIGINS=* in production. The backend will log a warning if permissive CORS is enabled.

Session & Token Security

Firewall Rules

πŸ”Œ Default Ports:
  • Backend API: Port 3000
  • Frontend Web: Port 5000 (or 3000 in dev mode)
  • SSH: Port 22
  • HTTP: Port 80 (for nginx proxy)
  • HTTPS: Port 443 (for nginx proxy with SSL)

Option A: With Nginx Reverse Proxy (Recommended)

If using nginx as a reverse proxy, you only need to open ports 80 and 443. Nginx will forward requests to the backend (3000) and frontend (5000) internally.

UFW - With Nginx Proxy
# Allow SSH
sudo ufw allow 22

# Allow HTTP/HTTPS (nginx handles proxying)
sudo ufw allow 80
sudo ufw allow 443

# Backend (3000) and Frontend (5000) stay internal
# No need to expose them - nginx proxies the traffic

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status

Option B: Without Reverse Proxy (Direct Access)

If you're NOT using nginx/Caddy and want to access the services directly, you must open the backend and frontend ports:

UFW - Direct Access (No Proxy)
# Allow SSH
sudo ufw allow 22

# Allow Backend API (Rust/Axum)
sudo ufw allow 3000

# Allow Frontend Web (Next.js)
sudo ufw allow 5000

# Optional: Also allow 80/443 if you plan to add nginx later
sudo ufw allow 80
sudo ufw allow 443

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status

⚠️ Security Warning

Exposing ports 3000 and 5000 directly is not recommended for production because:

  • No SSL/HTTPS encryption (data sent in plain text)
  • No rate limiting or DDoS protection
  • Exposes internal service ports to the internet

Recommended: Use nginx or Caddy as a reverse proxy with SSL certificates (Let's Encrypt).

Port Summary Table

Port Service With Nginx Without Nginx
22 SSH βœ… Open βœ… Open
80 HTTP (nginx) βœ… Open Optional
443 HTTPS (nginx + SSL) βœ… Open Optional
3000 Backend API ❌ Internal only βœ… Open
5000 Frontend Web ❌ Internal only βœ… Open

Quick Test (Without Firewall Changes)

To quickly test if the services are accessible:

Terminal
# Test backend locally
curl http://localhost:3000/api/health

# Test backend from another machine (replace YOUR_SERVER_IP)
curl http://YOUR_SERVER_IP:3000/api/health

# Test frontend
curl http://YOUR_SERVER_IP:5000

# If connection refused, open the ports:
sudo ufw allow 3000
sudo ufw allow 5000

Production Deployment

For a production environment, we recommend using Nginx as a reverse proxy and SSL terminator. This allows you to serve both the frontend and backend on standard ports (80/443) with a custom domain.

1. Nginx Reverse Proxy Configuration

/etc/nginx/sites-available/streamcore
server {
    listen 80;
    server_name yourdomain.com api.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

# Frontend (yourdomain.com)
server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

# Backend API (api.yourdomain.com)
server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

2. Process Management

Ensure you have configured the Systemd services as described in the Systemd Services section. This will ensure your application starts automatically and restarts on failure.

Enable services
sudo systemctl enable iptv-backend
	sudo systemctl enable streamcore-frontend
	sudo systemctl start iptv-backend
	sudo systemctl start streamcore-frontend

3. SSL Certificates (Let's Encrypt)

Generate free SSL certificates using Certbot:

Terminal
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d api.yourdomain.com

Android App Build Guide

Build the native Android TV app from source code.

Modules: TV app in Apps/tv_app, phone app in Apps/phone_app. This section focuses on TV build flow; the phone app follows the same Gradle process.

Prerequisites

Requirement Version Notes
Android Studio Hedgehog (2023.1.1) or newer Download
JDK 17+ Bundled with Android Studio
Android SDK API 35 (Android 15) Compile & Target SDK
Min SDK API 24 (Android 7.0) Minimum supported
Gradle 8.2+ Bundled with project

1. Open Project

  1. Open Android Studio
  2. Select "Open" and navigate to Apps/tv_app
  3. Wait for Gradle sync to complete (may take several minutes)
  4. If prompted, install any missing SDK components

2. Configure Backend URL

Apps/tv_app/local.properties
# Copy from template
cp local.properties.template local.properties

# Edit with your backend URL
backend.url=https://api.yourdomain.com

# For local development with emulator:
# backend.url=http://10.0.2.2:3000

# For local development with physical device:
# backend.url=http://YOUR_COMPUTER_IP:3000

3. Configure App Identity (Optional)

To customize the app package name and branding:

πŸ“„ Apps/tv_app/app/build.gradle
build.gradle (app)
android {
    namespace 'com.yourcompany.yourbrand'
    
    defaultConfig {
        applicationId 'com.yourcompany.yourbrand'
        // ...
    }
}
Note: The project uses Groovy DSL (build.gradle), not Kotlin DSL. Use single quotes without = signs in Groovy syntax.

4. Build Debug APK

Terminal (from Apps/tv_app)
# Using Gradle wrapper
./gradlew assembleDebug

# APK output location:
# app/build/outputs/apk/debug/app-debug.apk

Or in Android Studio: Build β†’ Build Bundle(s) / APK(s) β†’ Build APK(s)

5. Build Release APK/AAB

Generate Signing Key (first time only)

Terminal
keytool -genkey -v -keystore release-key.jks -keyalg RSA \
  -keysize 2048 -validity 10000 -alias release

# Follow prompts to set passwords
# Store release-key.jks securely - you need it for all future updates!

Configure Signing

Apps/tv_app/keystore.properties (create this file)
storePassword=your_keystore_password
keyPassword=your_key_password
keyAlias=release
storeFile=../release-key.jks

Build Release

Terminal
# Build signed APK
./gradlew assembleRelease

# Build Android App Bundle (for Play Store)
./gradlew bundleRelease

# Output locations:
# APK: app/build/outputs/apk/release/app-release.apk
# AAB: app/build/outputs/bundle/release/app-release.aab

6. Install on Device

Terminal
# Install debug APK via ADB
adb install app/build/outputs/apk/debug/app-debug.apk

# Install release APK
adb install app/build/outputs/apk/release/app-release.apk

# For Android TV, enable ADB debugging in TV settings first

⚠️ Important Notes

  • Keep your keystore safe! Losing it means you can't update your app
  • Never commit keystore.properties to version control
  • Test on real devices before release, especially Android TV

Android App Features

StreamCore includes Android TV and Android Phone apps, both built with Kotlin and Jetpack Compose.

Device Registration

  1. Launch the app and log in
  2. Enter a device name and register it
  3. If you are at the device limit, select a device to remove
  4. Once registered, the device is linked to your account

Navigation

Player Features

Content Sections

Architecture

The app follows Clean Architecture with MVVM pattern:

Offline Support

API Reference

The backend exposes a RESTful API at /api.

πŸ“– API Reference
This section covers key endpoints. The backend provides a comprehensive REST API for admin, reseller, content, streaming, and TMDB integration.

Authentication

Endpoint Method Description
/api/auth/login POST Login with username/password, returns JWT access token
/api/auth/refresh POST Refresh access token using the current valid token
/api/auth/logout POST Invalidate current session
/api/auth/2fa/setup POST Initialize 2FA setup, returns QR code
/api/auth/2fa/verify POST Verify 2FA code during login
/api/auth/forgot-password POST Request password reset email
/api/auth/verify-reset-token POST Verify password reset token validity
/api/auth/reset-password POST Set new password with valid token
/api/health GET Health check endpoint (no auth required)

Content

Endpoint Method Description
/api/content GET List all content (paginated)
/api/content/{id} GET Get content details
/api/content POST Create new content (admin)
/api/content/{id} PUT Update content (admin)
/api/content/{id} DELETE Delete content (admin)
/api/series/{id}/seasons GET Get series seasons with episodes
/api/delivery/discovery GET Get discovery overview (featured, recent, categories)

User Management

Endpoint Method Description
/api/admin/users GET List all users (admin only)
/api/reseller/users GET List reseller's users
/api/admin/users POST Create user (admin)
/api/reseller/users POST Create user (reseller)
/api/user/profile GET Get current user profile
/api/devices GET List user devices
/api/user/favorites GET/POST/DELETE Manage favorites

Additional Endpoints

Endpoint Method Description
/api/admin/smtp GET/PUT Get/Update SMTP configuration
/api/admin/smtp/test POST Test SMTP connection
/api/user/progress POST Save watch progress for resume
/api/user/progress/:id GET Get progress for content
/api/user/continue-watching GET Get continue watching list
/api/user/history GET Get viewing history log
/api/user/history/clear DELETE Clear watch history
/api/redeem/validate POST Validate gift code
/api/redeem POST Redeem gift code and create account
/api/demo POST Create demo account (public)
/api/demo/status GET Check if demo is enabled

Public API v1 (Reseller Integration)

The Public API v1 allows resellers to manage users programmatically using API keys. These endpoints use X-API-Key header authentication instead of JWT.

πŸ”‘ API Key Authentication
All /api/v1/* endpoints require a valid API key in the X-API-Key header. Create API keys from the Reseller β†’ API Keys section.

User Management Endpoints

Endpoint Method Permission Description
/api/v1/users GET users:read List users with filters, search, and pagination
/api/v1/users/{id} GET users:read Get user details by ID
/api/v1/users POST users:create Create a new user (deducts credits)
/api/v1/users/{id} PUT users:update Update user (email, password, max_devices, active)
/api/v1/users/{id}/extend POST users:extend Extend user subscription (deducts credits)
/api/v1/users/{id}/status PUT users:update Update user status (enable/disable)
/api/v1/users/{id}/reset-password POST users:update Reset user password (auto-generate or set custom)
/api/v1/users/{id}/categories GET users:read Get user with assigned categories
/api/v1/users/{id}/categories PUT users:categories Update user's content categories
/api/v1/users/{id} DELETE users:delete Delete a user

Categories & Credits Endpoints

Endpoint Method Permission Description
/api/v1/categories GET categories:read List all available content categories
/api/v1/credits/balance GET credits:read Get current credit balance
/api/v1/credits/calculate POST credits:read Calculate cost for an operation

Demo Management Endpoints

🎯 Demo Users
Demos are free trial accounts with time-limited access. Duration is set globally by admin (demo_duration_hours). Each reseller has a daily limit (daily_demo_limit) set by admin.
Endpoint Method Permission Description
/api/v1/demos GET demos:read List demo users (supports ?status=active|expired)
/api/v1/demos POST demos:create Create demo user (free, no credits)
/api/v1/demos/{id} GET demos:read Get demo details with categories
/api/v1/demos/{id} DELETE demos:delete Delete a demo user

List Users Query Parameters

Parameter Type Description
page integer Page number (default: 1)
limit integer Items per page (default: 50, max: 100)
search string Search by username or email
status string Filter: active, inactive, expired, expiring
expiring_days integer Users expiring within N days (default: 7 when status=expiring)
sort_by string Sort field: created_at, expires_at, username
sort_order string Sort order: asc, desc (default: desc)

Create User Request

POST /api/v1/users
{
  "username": "newuser123",
  "password": "securepassword",
  "email": "user@example.com",        // optional
  "subscription_months": 3,
  "max_devices": 5,
  "categories": [1, 2, 3]             // optional, category IDs
}

Extend Subscription Request

POST /api/v1/users/{id}/extend
{
  "days": 30                          // number of days to add
}

Calculate Cost Request

POST /api/v1/credits/calculate
{
  "operation": "create_user",
  "months": 3,
  "devices": 5
}

// or for extension
{
  "operation": "extend_user",
  "days": 30,
  "devices": 5
}

Success Response

User Created Response
{
  "success": true,
  "user": {
    "id": 123,
    "username": "newuser123",
    "expires_at": "2026-03-01T00:00:00Z",
    "max_devices": 5,
    "is_active": true
  },
  "credits_used": 4.5,
  "remaining_balance": 95.5
}

Update User Request

PUT /api/v1/users/{id}
{
  "email": "newemail@example.com",    // optional
  "password": "newpassword123",       // optional
  "max_devices": 5,                   // optional (1-10)
  "active": true                      // optional
}

Reset Password Request

POST /api/v1/users/{id}/reset-password
// Auto-generate password
{}

// Or set custom password
{
  "new_password": "MyCustomPassword123!"
}

Reset Password Response

Response
{
  "success": true,
  "new_password": "xK9#mNpQ2Rst",
  "message": "Password reset successfully"
}

Update User Categories

PUT /api/v1/users/{id}/categories
{
  "category_ids": [1, 2, 5, 8]    // Array of category IDs
}

Create Demo Request

POST /api/v1/demos
{
  "username": "demo_user",
  "password": "demo123456",
  "email": "demo@example.com",    // optional
  "category_ids": [1, 2, 4]       // optional, all categories if omitted
}

Demo Response

Response
{
  "id": 123,
  "username": "demo_user",
  "email": "demo@example.com",
  "active": true,
  "demo_expires_at": "2026-12-03T05:00:00Z",
  "created_at": "2026-12-02T17:00:00Z",
  "categories": [
    { "id": 1, "name": "VOD Movies", "type": "VOD" },
    { "id": 2, "name": "TV Channels", "type": "TV" },
    { "id": 4, "name": "Events", "type": "Eventos" }
  ]
}

List Demos with Filters

Examples
# List all demos
GET /api/v1/demos

# List only active demos
GET /api/v1/demos?status=active

# List expired demos
GET /api/v1/demos?status=expired

# With pagination
GET /api/v1/demos?page=1&limit=20

List Users with Filters

Examples
# Search users
GET /api/v1/users?search=john

# Get active users only
GET /api/v1/users?status=active

# Get users expiring in next 7 days
GET /api/v1/users?status=expiring&expiring_days=7

# Get expired users
GET /api/v1/users?status=expired

# Sort by expiration date
GET /api/v1/users?sort_by=expires_at&sort_order=asc

# Pagination
GET /api/v1/users?page=2&limit=25

Pagination Response

List Users Response
{
  "users": [...],
  "total": 150,
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 150,
    "total_pages": 3,
    "has_next": true,
    "has_prev": false
  }
}

Reseller API Keys Management

Endpoints for managing reseller API keys (require JWT authentication):

Endpoint Method Description
/api/reseller/api-keys GET List all API keys for current reseller
/api/reseller/api-keys POST Create new API key
/api/reseller/api-keys/{id} GET Get API key details
/api/reseller/api-keys/{id} PUT Update API key settings
/api/reseller/api-keys/{id} DELETE Delete API key
/api/reseller/api-keys/{id}/regenerate POST Regenerate API key secret
/api/reseller/api-keys/permissions GET List available permissions

Authentication Headers

For JWT-authenticated endpoints:

JWT Request Headers
Authorization: Bearer <access_token>
Content-Type: application/json

For Public API v1 endpoints:

API Key Request Headers
X-API-Key: <your_api_key>
Content-Type: application/json

Error Responses

Error Format
{
  "error": "Error message",
  "code": "ERROR_CODE",
  "status": 400
}
Status Description
400 Bad Request - Invalid input
401 Unauthorized - Invalid/expired token
403 Forbidden - Insufficient permissions
404 Not Found - Resource doesn't exist
429 Too Many Requests - Rate limited
500 Internal Server Error

Troubleshooting

Solutions to common issues you may encounter.

Backend Issues

Backend won't start

  • Check if port 3000 is already in use: lsof -i :3000
  • Verify Rust is installed: rustc --version
  • Check .env file exists and has correct values
  • Try: cargo clean && cargo build --release

Database connection failed

  • Check PostgreSQL service status: docker compose ps postgres
  • Verify DATABASE_URL matches your PostgreSQL user/password/database
  • Check PostgreSQL logs: docker compose logs -f postgres
  • Check DATABASE_URL format in .env

"Rust compilation errors"

  • Update Rust: rustup update
  • Clean build: cargo clean
  • Check for missing system dependencies (openssl-dev, pkg-config)

Frontend Issues

Frontend can't connect to backend

  • Verify NEXT_PUBLIC_API_URL in frontend .env.local
  • Check if backend is running: curl http://localhost:3000/api/health
  • Check CORS configuration if on different domains
  • Ensure no firewall blocking the connection

Blank page or "Loading..." forever

  • Open browser DevTools (F12) β†’ Console for errors
  • Check Network tab for failed API requests
  • Clear browser cache and localStorage
  • Try incognito/private browsing mode

"npm install" fails

  • Delete node_modules and package-lock.json
  • Run npm cache clean --force
  • Try npm install again
  • Ensure Node.js 20+ is installed

Authentication Issues

Can't login / "Invalid credentials"

  • Default admin: username admin, password from ADMIN_DEFAULT_PASSWORD env or check console for auto-generated password
  • Check if user exists and is not disabled
  • Check subscription hasn't expired
  • Clear browser cookies and try again

2FA not working

  • Ensure device time is synchronized (within 30 seconds)
  • Use backup codes if available
  • Admin can disable 2FA for a user in admin panel

Payment Issues

Stripe webhooks not working

  • Verify webhook URL is publicly accessible
  • Check STRIPE_WEBHOOK_SECRET matches Stripe dashboard
  • Test with Stripe CLI: stripe listen --forward-to localhost:3000/api/payments/stripe/webhook
  • Check backend logs for webhook errors

Credits not added after payment

  • Check Stripe dashboard for payment status
  • Verify webhook is configured correctly
  • Check backend logs for errors
  • Admin can manually add credits if needed

Streaming Issues

Video playback issues

  • Ensure stream URLs are accessible from client
  • Check browser console for CORS errors
  • Verify HLS/DASH streams are properly formatted
  • Test stream URL directly in a desktop media player (VLC, MPV)

Buffering or slow playback

  • Check stream server bandwidth
  • Try lower quality if available
  • Check client internet connection
  • Consider using a CDN for content delivery

Android App Issues

Android TV/Phone app can't connect

  • Create Apps/tv_app/local.properties from local.properties.template and set backend.url
  • For phone builds, also configure Apps/phone_app/local.properties
  • For emulator use: backend.url=http://10.0.2.2:3000
  • Ensure backend allows HTTP (or configure HTTPS)
  • Check network_security_config.xml for cleartext traffic settings

Device registration fails

  • Ensure device has internet connection
  • Check if user has reached device limit
  • Try uninstalling and reinstalling the app
  • Check backend logs for errors

Login Backdrops (Frontend)

Customize the hero images shown on the login screen.

  1. Add your images to frontend/public/backdrops/ (recommended: PNG/WebP, 1280Γ—720 or 1920Γ—1080).
  2. Option A (no code changes): Replace the existing backdrop-*.png files while keeping the same filenames.
  3. Option B (edit from the Admin UI): Admin β†’ System Configuration β†’ Login Backdrops. Paste a comma/newline-separated list of URLs or /backdrops/* paths. This saves ui_login_series_backdrops / ui_login_movies_backdrops in the database and the login page reads them from GET /api/public/config/ui.
  4. Option C (defaults in code): Edit frontend/src/constants/backdrops.ts (arrays SERIES_BACKDROPS / MOVIES_BACKDROPS).
  5. Use royalty-free or owned assets. If you generate images with AI, keep proof of your generator’s commercial license/TOS for marketplace compliance.
  6. After changing assets/config, rebuild the frontend: npm run build then npm run start (or your deploy pipeline).

Frequently Asked Questions

What are the minimum system requirements?

For a basic deployment: 2GB RAM, 10GB storage, 1 CPU core. For production with 1000+ users: 4GB+ RAM, SSD storage, 2+ CPU cores recommended.

Can I use a different database?

The current stack is designed for PostgreSQL. Using a different database engine requires custom development and is outside the standard package scope.

How do I change the admin password?

Login as admin β†’ Profile (top right) β†’ Change Password. If the password is lost, use the password reset flow (SMTP) or update the stored hash in PostgreSQL (see Backend Environment section).

What video formats are supported?

HLS (.m3u8), DASH (.mpd), and direct MP4/MKV streams. HLS is recommended for best compatibility across all platforms.

How do I enable HTTPS?

Use Nginx as a reverse proxy with Let's Encrypt certificates. See the Deployment section for configuration.

Can I run multiple instances for high availability?

Yes, with PostgreSQL and proper infrastructure. Use a shared database instance and put frontend/backend behind a load balancer or reverse proxy.

How do I backup the database?

Use PostgreSQL backup tools, for example: pg_dump "$DATABASE_URL" > backup/iptv_$(date +%Y%m%d).sql. You can also enable automatic backups via BACKUP_ENABLED / BACKUP_DIR in backend/.env.

What browsers are supported?

Chrome 80+, Firefox 75+, Safari 13+, Edge 80+. Mobile browsers (Chrome/Safari on iOS/Android) are also supported.

Can I customize the UI colors/theme?

Yes! Edit the CSS variables in frontend/src/app/globals.css or the Tailwind config. The app supports both dark and light themes.

How do I add new languages?

Add translation files in frontend/src/locales/. Copy an existing locale folder (e.g., en.json) and translate the strings. Update the language selector in i18n.ts.

Is the Android app compatible with Android TV?

Yes. StreamCore includes a dedicated Android TV app (Apps/tv_app) with Leanback and D-pad navigation, and a dedicated Android Phone app (Apps/phone_app) for phone/tablet UX.

How does the credit system work?

Resellers purchase credits via Stripe. Creating users costs credits based on subscription months and device count: months Γ— (1 + (devices - 3) Γ— 0.25). Example: 1 month with 3 devices = 1 credit. Volume discounts apply to bulk purchases.

Can I disable certain features?

Yes, many features can be toggled in Admin β†’ Settings. You can also hide UI elements by editing the frontend components.

How do I import content from M3U playlists?

Go to Admin β†’ Content β†’ Import, paste your M3U/M3U8 URL, and the system will parse and import all channels with categories.

What's the device limit per user?

Configurable per user (default 1-5). Admin can set global defaults in Settings. Users can manage their devices in their profile.

Credits & Licenses

StreamCore is built with the following open-source libraries and services:

Frontend (Web)

Library License Purpose
Next.js MIT React framework
React MIT UI library
Tailwind CSS MIT Utility-first CSS
shadcn/ui MIT UI components
Lucide Icons ISC Icon library
hls.js Apache 2.0 HLS playback
Shaka Player Apache 2.0 DASH/HLS playback
i18next MIT Internationalization

Backend (Rust)

Library License Purpose
Axum MIT Web framework
Tokio MIT Async runtime
Serde MIT/Apache 2.0 Serialization
SQLx MIT/Apache 2.0 Database
jsonwebtoken MIT JWT authentication
Lettre MIT Email sending

Android App (Kotlin)

Library License Purpose
Jetpack Compose Apache 2.0 UI toolkit
AndroidX Media3 Apache 2.0 Video playback (ExoPlayer successor)
Media3 ExoPlayer Apache 2.0 Video playback engine
FFmpeg Extension Apache 2.0 Software decoding fallback
Hilt Apache 2.0 Dependency injection
Retrofit Apache 2.0 HTTP client
Coil Apache 2.0 Image loading

Third-Party Services

Service Purpose
Stripe Payment processing
TMDB Movie/TV metadata
Google Fonts Inter & JetBrains Mono fonts

Fonts

Support

Getting Help

If you encounter issues not covered in this documentation:

  1. Check the Troubleshooting section
  2. Review the FAQ
  3. Check backend/frontend logs for error messages
  4. Search existing issues on the support portal

Reporting Issues

When reporting issues, please include:

Feature Requests

We welcome feature requests and suggestions. Please describe:

πŸ“§ Support Contact
For technical support, please use the support system on the marketplace where you purchased StreamCore.

Thank You!

Once again, thank you for purchasing StreamCore IPTV. We hope this documentation has been helpful. If you have any questions or need assistance, please don't hesitate to reach out through the CodeCanyon support system.

We appreciate your business and wish you success with your streaming platform!

- The Syruum Team

Back to Top